package jee.boot.module.bpm.table.mysql;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jee.boot.common.utils.MapUtils;
import jee.boot.common.utils.StringUtils;
import jee.boot.entity.bpm.BpmConstant;
import jee.boot.module.bpm.dao.MysqlTableOperatorDao;
import jee.boot.entity.bpm.BusinessColumn;
import jee.boot.entity.bpm.BusinessTable;
import jee.boot.module.bpm.table.TableExecutor;
import jee.boot.module.bpm.table.mysql.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;


/**
 * Mysql数据库操作类
 */
public class MysqlTableExecutor implements TableExecutor {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private MysqlTableOperatorDao mysqlTableOperatorDao;

    public MysqlTableExecutor(MysqlTableOperatorDao mysqlTableOperatorDao) {
        this.mysqlTableOperatorDao = mysqlTableOperatorDao;
    }

    /**
     * 检查表是否存在
     *
     * @param formTable table.name 需设置表名
     * @return
     */
    @Override
    public int existTable(FormTable formTable) {
        return mysqlTableOperatorDao.existTable(formTable);
    }

    /**
     * 创建表
     *
     * @param formTable table信息,以及column信息
     */
    @Override
    public void createTable(FormTable formTable) {
        mysqlTableOperatorDao.createTable(formTable);
    }

    /**
     * 删除表
     *
     * @param formTable
     */
    @Override
    public void dropTable(FormTable formTable) {
        mysqlTableOperatorDao.dropTable(formTable);
    }

    /**
     * 修改表注释
     *
     * @param formTable
     */
    @Override
    public void alterTableComment(FormTable formTable) {
        mysqlTableOperatorDao.alterTableComment(formTable);
    }

    /**
     * 添加字段
     *
     * @param formTable table.columnList是需要被添加的字段
     */
    @Override
    public void addColumn(FormTable formTable) {
        mysqlTableOperatorDao.addColumn(formTable);
    }

    /**
     * 修改字段
     *
     * @param formTable table.columnList是需要被修改的字段
     */
    @Override
    public void modifyColumn(FormTable formTable) {
        mysqlTableOperatorDao.modifyColumn(formTable);
    }

    /**
     * 删除字段
     *
     * @param formTable table.columnList是需要被删除的字段
     */
    @Override
    public void dropColumn(FormTable formTable) {
        mysqlTableOperatorDao.dropColumn(formTable);
    }

    /**
     * 查看表信息
     *
     * @param formTable
     * @return
     */
    @Override
    public FormTable findTable(FormTable formTable) {
        return mysqlTableOperatorDao.findTable(formTable);
    }

    /**
     * 查询数据库中已存在的表
     *
     * @param formTable
     * @return
     */
    @Override
    public List<FormTable> findTableList(FormTable formTable) {
        return mysqlTableOperatorDao.findTableList(formTable);
    }

    /**
     * 查看表所有列信息
     *
     * @param formTable
     * @return
     */
    @Override
    public List<Map<String, Object>> findTableColumns(FormTable formTable) {
        return mysqlTableOperatorDao.findTableColumns(formTable);
    }

    /**
     * 同步表结构
     * 1. 检查表是否创建
     * 1.1 如果没有创建则建表 -end
     * 1.2 已建表
     * 1.2.1 加载原始表结构数据
     * 1.2.2 表描述是否变更,如果是,则更新
     * 1.2.3 检查是否有新增字段,如果有,则新增
     * 1.2.4 检查是否有修改字段,如果有,则修改
     * 1.2.5 检查是否有删除字段,如果有,则删除
     *
     * @param table
     */
    @Override
    public void syncTable(BusinessTable table) {

        FormTable newTable = convertTable(table, true);
        // 1. 检查表是否创建
        int i = existTable(newTable);
        // 1.1 如果没有创建则建表 -end
        if (i < 1) {
            createTable(newTable);
        } else {
            // 1.2.1 加载原始表结构数据
            FormTable oldTable = findTable(newTable);
            // 1.2.2 表描述是否变更,如果是,则更新
            if (!StringUtils.equals(newTable.getComment(), oldTable.getComment())) {
                alterTableComment(newTable);
            }
            //加载原始表列信息
            List<Map<String, Object>> tableColumns = findTableColumns(newTable);
            if (tableColumns != null && !tableColumns.isEmpty()) {
                tableColumns.forEach(d -> {
                    FormField formField = convertColumn(d);
                    oldTable.getAllColumnList().add(formField);
                });
            }
            // 分析表结构
            analysisFields(oldTable, newTable);
            //1.2.3 检查是否有新增字段,如果有,则新增
            if (!newTable.getAddColumnList().isEmpty()) {
                addColumn(newTable);
            }
            // 1.2.4 检查是否有修改字段,如果有,则修改
            if (!newTable.getModifyColumnList().isEmpty()) {
                modifyColumn(newTable);
            }
            // 1.2.5 检查是否有删除字段,如果有,则删除
            if (!newTable.getDropColumnList().isEmpty()) {
                dropColumn(newTable);
            }
        }
    }

    /**
     * 转换表
     *
     * @param table
     * @return
     */
    private FormTable convertTable(BusinessTable table) {
        return convertTable(table, false);
    }

    /**
     * 转换表
     *
     * @param table
     * @param convertColumn
     * @return
     */
    private FormTable convertTable(BusinessTable table, boolean convertColumn) {
        FormTable formTable = new FormTable();
        formTable.setName(table.getName());
        formTable.setComment(table.getComment());
        if (convertColumn) {
            List<Map<String, Object>> columnList = table.getColumnList();
            if (columnList != null && !columnList.isEmpty()) {
                columnList.forEach(column -> {
                    FormField formField = convertColumn(column);
                    formTable.getAllColumnList().add(formField);
                });
            }
        }
        return formTable;
    }

    /**
     * 转换成Field
     *
     * @param map
     * @return
     */
    private FormField convertColumn(Map<String, Object> map) {
        BusinessColumn businessColumn = MapUtils.toBean(map,BusinessColumn.class);//JsonMapper.fromJsonString(JsonMapper.toJsonString(map), BusinessColumn.class);
        // 检查类型
        String type = businessColumn.getDataType();
        FormField field = null;
        switch (type) {
            case BpmConstant.BPM_COLUMN_DATA_TYPE_NUMBER:
                if (businessColumn.getAccuracy() > 0) {
                    field = new DecimalField();
                } else {
                    field = new IntegerField();
                }
                break;
            case BpmConstant.BPM_COLUMN_DATA_TYPE_LONGTEXT:
                field = new TextField();
                break;
            case BpmConstant.BPM_COLUMN_DATA_TYPE_DATE:
                field = new DateTimeField();
                break;
            case BpmConstant.BPM_COLUMN_DATA_TYPE_FILE:
                field = new FileField();
                break;
            case BpmConstant.BPM_COLUMN_DATA_TYPE_STRING:
            default:
                field = new StringField();

        }
        field.setColumnName(businessColumn.getColumnName());
        field.setFieldName(StringUtils.toCamelCase(field.getColumnName()));
        field.setFieldType(type);
        field.setCreate(BpmConstant.SYS_YES.equals(businessColumn.getCreate()));
        field.setAccuracy(businessColumn.getAccuracy());
        field.setLength(businessColumn.getLength());
        field.setNullable(BpmConstant.SYS_NO.equals(businessColumn.getRequired()));
        field.setDefaultValue(businessColumn.getDefaultValue());
        field.setComment(businessColumn.getComment());
        field.setPrimaryKey(BpmConstant.SYS_YES.equals(businessColumn.getPrimaryKey()));

        return field;
    }

    /**
     * 分析需要新增的字段
     *
     * @param oldModel 旧的模型
     * @param newModel 新的模型
     */
    private void analysisFields(FormTable oldModel, FormTable newModel) {
        List<FormField> oldColumns = oldModel.getAllColumnList();
        List<FormField> newColumns = newModel.getAllColumnList();
        Map<String, FormField> delMap = Maps.newHashMap();
        oldColumns.forEach(o -> {
            delMap.put(o.getColumnName(), o);
        });
        for (FormField newColumn : newColumns) {
            boolean add = false;
            boolean modify = false;
            boolean findInOld = false;
            for (FormField oldColumn : oldColumns) {
                if (StringUtils.equals(oldColumn.getColumnName(), newColumn.getColumnName())) {
                    // 匹配上,则表示新表中也有这个字段,不需删除,从删除列表中删除
                    if (delMap.containsKey(oldColumn.getColumnName())) {
                        delMap.remove(oldColumn.getColumnName());
                    }
                    //匹配上,表示新旧中都有这个字段,不需要添加了
                    findInOld = true;
                    if (!oldColumn.equals(newColumn)) {
                        modify = true;
                    }
                }
            }
            // 在old中没有找到new的数据
            if (!findInOld) {
                add = true;
            }
            if (add && newColumn.getCreate()) {
                newModel.getAddColumnList().add(newColumn);
            }
            if (modify && newColumn.getCreate()) {
                newModel.getModifyColumnList().add(newColumn);
            }
        }
        if (!delMap.isEmpty()) {
            newModel.setDropColumnList(Lists.newArrayList(delMap.values()));
        }
    }


}
